emacs org快速选择代码块
这是我org笔记中用来快速选择,不同代码块的一个功能。我模仿了vim那样按下 Ctrl+c S 键就进入一个选择模式,然后按下 j k 可以用来选择上下文不同的代码块,按 y或者enter 选择复制文本,按 q 退出,就好像这是一个vim功能的模式一样。
原理就是建立一个org-quick-select-temp-keymap的map,然后把原本的map用org-quick-select-original-keymap保存。然后通过org-quick-select-disable-other-keys,把buffer设置成只读模式,并且映射一些临时的键就起到了构建一个类似vim mode那样的模式了。
(defvar org-quick-select-temp-keymap nil) (defvar org-quick-select-restrict-mode nil) ; 用来标记是否启用了限制模式 (defvar org-quick-select-original-keymap nil) ; 保存原始的 keymap (defun org-quick-select-toggle-restrict-keys () "切换限制按键的状态,按下 C-c S 时启用或关闭限制模式,仅在 org-mode 中生效。" (interactive) (if (not (derived-mode-p 'org-mode)) (message "此功能仅在 org-mode 中可用。") (if org-quick-select-restrict-mode (org-quick-select-enable-all-keys) ; 如果限制模式已启用,按下时解除限制 (org-quick-select-disable-other-keys)))) ; 否则启用限制模式 (defun org-quick-select-disable-other-keys () "屏蔽所有其他按键,仅允许 j/k 控制光标上下移动,并禁用输入,仅在 org-mode 中生效。" (interactive) (if (not (derived-mode-p 'org-mode)) (message "此功能仅在 org-mode 中可用。") ;; 保存当前的 keymap 到 org-quick-select-original-keymap (setq org-quick-select-original-keymap (current-local-map)) ;; 创建一个临时的keymap (setq org-quick-select-temp-keymap (make-sparse-keymap)) ;; 只允许 'j', 'k' 控制上下移动 (define-key org-quick-select-temp-keymap (kbd "j") 'org-select-src-block-content-next) (define-key org-quick-select-temp-keymap (kbd "k") 'org-select-src-block-content-prev) ;; 将 M-w 映射为复制当前选择内容 (define-key org-quick-select-temp-keymap (kbd "M-w") 'org-quick-select-copy-selection) ;; 将 y 映射为复制当前选择内容 (define-key org-quick-select-temp-keymap (kbd "y") 'org-quick-select-copy-selection) ;; 将 Enter 键映射为复制当前选择内容 (define-key org-quick-select-temp-keymap (kbd "RET") 'org-quick-select-copy-selection) (define-key org-quick-select-temp-keymap (kbd "q") 'org-quick-select-toggle-restrict-keys) ;; 禁用其它键,防止意外的按键操作 (use-local-map org-quick-select-temp-keymap) ;; 启用只读模式,禁用其他输入 (setq buffer-read-only t) (setq org-quick-select-restrict-mode t) ;; 设置标记为限制模式已启用 (message "键盘被限制,只有 j/k 可用,按 C-c S 解除限制。"))) (defun org-quick-select-copy-selection () "拷贝当前选择的内容到剪贴板。" (interactive) (if (use-region-p) (progn (kill-ring-save (region-beginning) (region-end)) ;; 拷贝选中的内容 (message "已拷贝选择的内容")) (message "没有选择任何内容。"))) (defun org-select-src-block-content-next () "搜索下一个 code block,跳转到位置并全选内容,排除 'begin_src' 和 'end_src'。" (interactive) (let ((start (point))) ;; 搜索下一个 'begin_src',跳到该位置 (if (re-search-forward "^#\\+begin_src" nil t) (progn ;; 跳过 'begin_src' 之前的部分 (forward-line 1) ;; 搜索 'end_src',选择从 'begin_src' 到 'end_src' 之间的内容 (let ((end (save-excursion (re-search-forward "^#\\+end_src" nil t) (point-at-bol)))) ;; 使用 point-at-bol 获取当前行的开始位置 (push-mark (point) t t) (goto-char end) (activate-mark))) ;; 如果没有找到下一个 code block,则给出提示 (message "没有找到下一个 code block")))) (defun org-select-src-block-content-prev () "搜索上一个 code block,跳转到位置并全选内容,排除 'begin_src' 和 'end_src'。" (interactive) (let ((start (point))) ;; 搜索上一个 'end_src' (if (re-search-backward "^#\\+end_src" nil t) (progn ;; 搜索对应的 'begin_src' (if (re-search-backward "^#\\+begin_src" nil t) (progn ;; 跳过 'begin_src' 行 (forward-line 1) (let ((begin (point)) (end (save-excursion (re-search-forward "^#\\+end_src" nil t) (point-at-bol)))) (push-mark (point) t t) (goto-char end) (activate-mark))) (message "没有找到对应的 begin_src")) ) ;; 如果没有找到上一个 code block,则给出提示 (message "没有找到上一个 code block")))) (defun org-quick-select-enable-all-keys () "恢复所有按键并解除输入限制,仅在 org-mode 中生效。" (interactive) (if (not (derived-mode-p 'org-mode)) (message "此功能仅在 org-mode 中可用。") ;; 恢复原始的 keymap (use-local-map org-quick-select-original-keymap) ;; 解除只读模式,允许输入 (setq buffer-read-only nil) (setq org-quick-select-restrict-mode nil) ;; 设置标记为限制模式已解除 (message "已恢复所有按键和输入功能。")))